/**
 * Created by ari on 1/14/2015.
 */
var WebSocketServer = require('websocket').server;
var http = require("http"),
    fs	 = require("fs"),
    readline = require('readline'),
    url = require('url'),
    qs = require('querystring');

var activeRequests = [];
var pathOffsets = {};

var CLIENT_PORT = 7845;
var EVENT_PORT = 7844;

var TIMEOUT_MAX = 5000;

var COMMAND_ADD = 'add';
var COMMAND_PATH = 'path';
var COMMAND_ERROR = 'error';


var server = http.createServer(function(request, response) {
    // process HTTP request. Since we're writing just WebSockets server
    // we don't have to implement anything.
});
server.listen(CLIENT_PORT, function() { });
console.log('Server running at :' + CLIENT_PORT + '/');

// create the server
wsServer = new WebSocketServer({
    httpServer: server
});

// WebSocket server
wsServer.on('request', function(request) {
    var connection = request.accept(null, request.origin);

    console.log("New Client connection: " + request.url);
    var url_parts = url.parse(request.url, true);

    var paths = query.path || '';
    if(typeof paths === 'string')
        paths = paths.split(';');

    for(var i=0; i<paths.length; i++) {
        if(typeof paths[i] === 'string')
            paths[i] = paths[i].split(',');
        var path = paths[i][0];
        var offset = parseInt(paths[i][1]);
        pathOffsets[path] = offset;
        paths[i] = path;

        watchFile(request, connection, path, offset);
    }

    // This is the most important callback for us, we'll handle
    // all messages from users here.
    connection.on('message', function(message) {
        console.log('message', message);
        if (message.type === 'utf8') {
            // process WebSocket message
        }
    });

    connection.on('close', function(connection) {
        console.log('close', message);
        // close user connection
    });
});
//
//
//
//http.createServer(function(request, response) {
//    var path = request.url;
//    if(!path.match(/\.log$/))
//        throw new Error("Invalid log path");
//    var url_parts = url.parse(request.url, true);
//    var query = url_parts.query;
//    var content = request.body;
//    var matchedRequests = [];
//    var filePath = request.url;
//    for(var i=0; i<activeRequests.length; i++) {
//        var info = activeRequests[i];
//        var paths = info[2];
//        if(paths.indexOf(filePath) >= 0)
//            matchedRequests[matchedRequests.length] = info;
//    }
//    request.on('data', function (data) {
//        for(var i=0; i<matchedRequests.length; i++) {
//            var info = matchedRequests[i];
//            var req = info[0];
//            var res = info[1];
//            var paths = info[2];
//            var offset = pathOffsets[filePath];
//            if(!offset)
//                throw new Error("Path missing offset");
//
//            console.log("Writing to " + req.url);
//            response.write("id: " + COMMAND_PATH + "\n");
//            response.write("data: " + filePath + ":" + offset + "\n");
//            res.write(data);
//            pathOffsets[filePath] = offset + data.length;
//            console.log("Updated offset: " + pathOffsets[filePath] + ' - ' + filePath);
//        }
//        //
//        //// Too much POST data, kill the connection!
//        //if (body.length > 1e6)
//        //    request.connection.destroy();
//    });
//
//}).listen(EVENT_PORT);
//console.log('Server running at :' + EVENT_PORT + '/');


function writeLine(response, args) {
    response.write("event: line\ndata: " + args.join(' ') + "\n\n"); // TODO: proper eventsource
    console.log("event: line\ndata: " + args.join(' '));
}

function watchFile(request, response, filePath, offset) {
    console.log("Checking path: " + filePath + ":" + offset);
    var stats = fs.statSync(filePath);

    if (stats.size < offset) {
        writeLine(response, [COMMAND_ERROR, "Size (" + stats.size + ") < Offset (" + offset + ")"]);
        console.error("Size (" + stats.size + ") < Offset (" + offset + ")");
        return false;
    }

    // if the file is changed
    if (stats.size > offset) {
        console.log("Size (" + stats.size + ") > Offset (" + offset + ")");

        // read it
        var fd = fs.openSync(filePath, 'r');
        var instream = fs.createReadStream(filePath, {
            encoding: 'utf-8',
            bufferSize: 1024,
            start: offset,
            end: stats.size,
            fd: fd
        });

        var rl = readline.createInterface({
            input: instream,
            terminal: false
        });
        response.write("event: path\ndata: " + filePath + ":" + stats.size + "\n\n");
        console.log("event: path\ndata: " + filePath + ":" + stats.size + "\n\n");

        rl.on('line', function(line) {
            writeLine(response, [line]);
        });

        rl.on('close', function(line) {
            response.write("event: eof\ndata: " + filePath + ":" + stats.size + "\n\n");
            console.log("event: eof\ndata: " + filePath + ":" + stats.size + "\n\n");
        });

        offset = stats.size;
        pathOffsets[filePath] = offset;
        console.log("Updated offset: " + pathOffsets[filePath] + ' - ' + filePath);
    }

    fs.watchFile(filePath, {
            persistent: true,
            interval: 100
        },
        function(curr, prev) {
            if (curr.size <= prev.size) {
                console.error("size: %d <= %d", prev.size, curr.size);
                return;
            }
            console.log("size: %d > %d", prev.size, curr.size);

            var fd = fs.openSync(filePath, 'r');

            var instream = fs.createReadStream(filePath, {
                encoding: 'utf-8',
                bufferSize: 1024,
                start: prev.size,
                end: curr.size,
                fd: fd
            });

            var rl = readline.createInterface({
                input: instream,
                terminal: false
            });
            response.write("event: path\ndata: " + filePath + ":" + stats.size + "\n\n");
            console.log("event: path\ndata: " + filePath + ":" + stats.size + "\n\n");

            rl.on('line', function(line) {
                writeLine(response, [line]);
            });
            rl.on('error', function(line) {
                writeLine(response, [COMMAND_ERROR, line]);
            });

            rl.on('close', function(line) {
                response.write("event: eof\ndata: " + filePath + ":" + stats.size + "\n\n");
                console.log("event: eof\ndata: " + filePath + ":" + stats.size + "\n\n");
            });

        }
    );

    response.on('close', function() {
        console.log("Unwatching: " + filePath);
        fs.unwatchFile(filePath);
    });

    console.log("Watching path: " + filePath + ":" + offset);
}
